package com.storm.lib.util;

import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * 
 * 类功能: 类似于OpenSessionViewFilter在非Web环境的实现
 * @author johnny
 * @version 2010-11-26
 */
public class OpenSessionUtil {
	
		public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory";

		private static OpenSessionUtil instance;

		private String sessionFactoryBeanName = DEFAULT_SESSION_FACTORY_BEAN_NAME;

		private boolean singleSession = true;

		private FlushMode flushMode = FlushMode.AUTO;

		private SessionFactory sessionFactory = null;
		private Session session = null;
		/**
		 * Set the bean name of the SessionFactory to fetch from Spring's
		 * root application context. Default is "sessionFactory".
		 * @see #DEFAULT_SESSION_FACTORY_BEAN_NAME
		 */
		public void setSessionFactoryBeanName(String sessionFactoryBeanName) {
			this.sessionFactoryBeanName = sessionFactoryBeanName;
		}

		/**
		 * Return the bean name of the SessionFactory to fetch from Spring's
		 * root application context.
		 */
		protected String getSessionFactoryBeanName() {
			return this.sessionFactoryBeanName;
		}

		/**
		 * Set whether to use a single session for each request. Default is "true".
		 * <p>If set to "false", each data access operation or transaction will use
		 * its own session (like without Open Session in View). Each of those
		 * sessions will be registered for deferred close, though, actually
		 * processed at request completion.
		 * @see SessionFactoryUtils#initDeferredClose
		 * @see SessionFactoryUtils#processDeferredClose
		 */
		public void setSingleSession(boolean singleSession) {
			this.singleSession = singleSession;
		}

		/**
		 * Return whether to use a single session for each request.
		 */
		protected boolean isSingleSession() {
			return this.singleSession;
		}

		/**
		 * Specify the Hibernate FlushMode to apply to this filter's
		 * {@link org.hibernate.Session}. Only applied in single session mode.
		 * <p>Can be populated with the corresponding constant name in XML bean
		 * definitions: e.g. "AUTO".
		 * <p>The default is "MANUAL". Specify "AUTO" if you intend to use
		 * this filter without service layer transactions.
		 * @see org.hibernate.Session#setFlushMode
		 * @see org.hibernate.FlushMode#MANUAL
		 * @see org.hibernate.FlushMode#AUTO
		 */
		public void setFlushMode(FlushMode flushMode) {
			this.flushMode = flushMode;
		}

		/**
		 * Return the Hibernate FlushMode that this filter applies to its
		 * {@link org.hibernate.Session} (in single session mode).
		 */
		protected FlushMode getFlushMode() {
			return this.flushMode;
		}



		public SessionFactory getSessionFactory() {
			return sessionFactory;
		}

		public void setSessionFactory(SessionFactory sessionFactory) {
			this.sessionFactory = sessionFactory;
		}

		public Session getSession() {
			return session;
		}

		public void setSession(Session session) {
			this.session = session;
		}

		public void openThreadSession(){
			SessionFactory sessionFactory = (SessionFactory) BeanUtil.getBean(getSessionFactoryBeanName());
			this.setSessionFactory(sessionFactory);
//			boolean participate = true;

			if (isSingleSession()) {
//				logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
				Session session = getSession(sessionFactory);
				this.setSession(session);
				TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
			}


//				if (!participate) {
//					if (isSingleSession()) {
//						// single session mode
//						SessionHolder sessionHolder =
//								(SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
////						logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
//						closeSession(sessionHolder.getSession(),this.getSessionFactory());
//					}
//					else {
//						// deferred close mode
//						SessionFactoryUtils.processDeferredClose(sessionFactory);
//					}
//				}

		}



		/**
		 * Get a Session for the SessionFactory that this filter uses.
		 * Note that this just applies in single session mode!
		 * <p>The default implementation delegates to the
		 * <code>SessionFactoryUtils.getSession</code> method and
		 * sets the <code>Session</code>'s flush mode to "MANUAL".
		 * <p>Can be overridden in subclasses for creating a Session with a
		 * custom entity interceptor or JDBC exception translator.
		 * @param sessionFactory the SessionFactory that this filter uses
		 * @return the Session to use
		 * @throws DataAccessResourceFailureException if the Session could not be created
		 * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
		 * @see org.hibernate.FlushMode#MANUAL
		 */
		protected Session getSession(SessionFactory sessionFactory){
			Session session = SessionFactoryUtils.getSession(sessionFactory, true);
			FlushMode flushMode = getFlushMode();
			if (flushMode != null) {
				session.setFlushMode(flushMode);
			}
			return session;
		}

		/**
		 * Close the given Session.
		 * Note that this just applies in single session mode!
		 * <p>Can be overridden in subclasses, e.g. for flushing the Session before
		 * closing it. See class-level javadoc for a discussion of flush handling.
		 * Note that you should also override getSession accordingly, to set
		 * the flush mode to something else than NEVER.
		 * @param session the Session used for filtering
		 * @param sessionFactory the SessionFactory that this filter uses
		 */
		public void closeThreadSession() {
			SessionFactoryUtils.closeSession(session);
		}
		public void closeSession(Session session, SessionFactory sessionFactory) {
			SessionFactoryUtils.closeSession(session);
		}

		public static OpenSessionUtil getInstance(){
			if (instance==null){
				instance = new OpenSessionUtil();
				return instance;
			}
			return instance;
		}

		private OpenSessionUtil() {
			super();
		}
	
		
	}


